using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Book.Blog.Core.Entities;
using Book.Blog.Core.Interfaces;
using Book.Blog.Infrastructure.Repositories;

namespace Book.Blog.Infrastructure.Data
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly BlogDbContext _context;
        private IDbContextTransaction? _transaction;
        private bool _disposed;

        private IRepository<User>? _users;
        private IRepository<Post>? _posts;
        private IRepository<Category>? _categories;
        private IRepository<Tag>? _tags;
        private IRepository<Comment>? _comments;
        private IRepository<PostHistory>? _postHistories;

        public UnitOfWork(BlogDbContext context)
        {
            _context = context;
        }

        public IRepository<User> Users => _users ??= new Repository<User>(_context);
        public IRepository<Post> Posts => _posts ??= new Repository<Post>(_context);
        public IRepository<Category> Categories => _categories ??= new Repository<Category>(_context);
        public IRepository<Tag> Tags => _tags ??= new Repository<Tag>(_context);
        public IRepository<Comment> Comments => _comments ??= new Repository<Comment>(_context);
        public IRepository<PostHistory> PostHistories => _postHistories ??= new Repository<PostHistory>(_context);

        public async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }

        public async Task BeginTransactionAsync()
        {
            _transaction = await _context.Database.BeginTransactionAsync();
        }

        public async Task CommitAsync()
        {
            try
            {
                if (_transaction != null)
                {
                    await _transaction.CommitAsync();
                }
            }
            catch
            {
                if (_transaction != null)
                {
                    await _transaction.RollbackAsync();
                }
                throw;
            }
            finally
            {
                if (_transaction != null)
                {
                    await _transaction.DisposeAsync();
                    _transaction = null;
                }
            }
        }

        public async Task RollbackAsync()
        {
            try
            {
                if (_transaction != null)
                {
                    await _transaction.RollbackAsync();
                }
            }
            finally
            {
                if (_transaction != null)
                {
                    await _transaction.DisposeAsync();
                    _transaction = null;
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                _context.Dispose();
                _transaction?.Dispose();
            }
            _disposed = true;
        }
    }
} 